package com.zst.dollars;

import ch.qos.logback.core.net.server.Client;
import com.zst.dollars.common.Consts;
import com.zst.dollars.entity.msg.ClientMsgRequestMessage;
import com.zst.dollars.entity.signin.ClientSignInRequestMessage;
import com.zst.dollars.handler.client.*;
import com.zst.dollars.handler.codec.FrameCodec;
import com.zst.dollars.handler.codec.decoder.ByteToMessageDecoder;
import com.zst.dollars.handler.codec.decoder.FrameDecoder;
import com.zst.dollars.handler.codec.encoder.FrameEncoder;
import com.zst.dollars.handler.codec.encoder.MessageToByteEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Scanner;
import java.util.UUID;

public class ClientApp {
    private static final Logger logger = LoggerFactory.getLogger(ClientApp.class);

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new FrameDecoder())
                                .addLast(new FrameEncoder())
                                .addLast(new ByteToMessageDecoder())
                                .addLast(new MessageToByteEncoder())
                                .addLast(new OutboundLogHandler())
                                .addLast(new ConnectionActiveHandler())
                                .addLast(new KeepAliveRequestHandler())
                                .addLast(new SignInResponseHandler())
                                .addLast(new MsgResponseHandler())
                                .addLast(new MsgInboundHandler());
                    }
                });

        ChannelFuture future = bootstrap.connect("127.0.0.1", Consts.port).sync();
        new ClientApp().userInterface(future.channel());

        future.channel().closeFuture().sync();
        group.shutdownGracefully();
    }

    /**
     * 处理用户互动
     */
    public void userInterface(Channel channel) {
        try{
            connectAction(channel);
            signInAction(channel);
            while(true){
                Scanner consoleInput = new Scanner(System.in);
                String msg = consoleInput.nextLine();
                String messageId = UUID.randomUUID().toString();
                ClientMsgRequestMessage msgRequestMessage = new ClientMsgRequestMessage(System.currentTimeMillis(), msg, channel.attr(Consts.tokenKey).get(), messageId);
                channel.writeAndFlush(msgRequestMessage);
                channel.attr(Consts.smeaphoreKey).get().acquire();
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e){
            logger.error("Exception：", e);
        }


    }

    /**
     * 处理连接过程
     * @param channel
     * @throws Exception
     */
    public void connectAction(Channel channel) throws Exception{
        int connectRetryCount = 0;
        while(StringUtils.isEmpty(channel.attr(Consts.tokenKey).get()) && connectRetryCount < Consts.clientConnectWaitCount){
            logger.info("正在连接服务器....");
            connectRetryCount++;
            Thread.sleep(1000l);
        }

        if(connectRetryCount >= Consts.clientConnectWaitCount){
            logger.info("连接服务端失败");
            channel.close();
            return;
        }
    }

    /**
     * 处理注册过程
     * @param channel
     */
    public void signInAction(Channel channel) throws InterruptedException {

        String username = "";
        Scanner consoleInput = new Scanner(System.in);

        while(StringUtils.isEmpty(username)){
            System.out.print("请输入用户名：");
            username = consoleInput.nextLine();
        }

        ClientSignInRequestMessage signInRequestMessage = newq ClientSignInRequestMessage(channel.attr(Consts.tokenKey).get(), username);
        channel.writeAndFlush(signInRequestMessage);
        channel.attr(Consts.smeaphoreKey).get().acquire();

        logger.info("注册成功");
    }
}
